Tutorial 4: visualizing bees

In this tutorial, you will learn how to use the contourplot_bees from the beeoptimal.plotting module. As its name suggests, the function allows plotting the positions of one or more bees over the function landscape.

For its basic usage, contourplot_bees requires the two following key inputs:

  • function: The objective function you are optimizing, provide as a BenchmarkFunction object.

  • bee_colony: A list of bees to plot (e.g., optimal bee or the entire colony at a given iteration).

Additional optional parameters can be specified to customize the plot, such as title, figsize, bounds, zoom, bee_marker_size, and optimal_solution.

[2]:
from beeoptimal.benchmarks import Schwefel2d
from beeoptimal.plotting import contourplot_bees
from beeoptimal import ArtificialBeeColony

Before plotting the bees, we need to optimize first our function (check the previous tutorial for details).

[3]:
ABC = ArtificialBeeColony(
    colony_size = 100,
    function    = Schwefel2d.fun,
    bounds      = Schwefel2d.bounds
    )

ABC.optimize(
    max_iters      = 1000,
    mutation       = 'ABC/best/1',
    stagnation_tol = 1e-6,
    verbose        = True,
    random_seed    = 12345)
Running Optimization:   2%|▏         |[00:00<00:05]
Early termination: Optimization stagnated at iteration 19 / 1000

One thing we might want to do is to visualize the optimal bee at the end of the optimization process:

[4]:
contourplot_bees(
    function   = Schwefel2d,
    bee_colony = [ABC.optimal_bee],
    title      = 'Optimal Bee after ABC optimization',
    )

Alternatively, we might want to visualize the entire colony at a given iteration. In the example below, we visualize the colony at initialization

[5]:
contourplot_bees(
    function         = Schwefel2d,
    bee_colony       = ABC.colony_history[0],
    title            = f"{Schwefel2d.name} contourplot with bees",
    figsize          = (600,600),
    bounds           = None,
    zoom             = 1.05,
    bee_marker_size  = 55,
    optimal_solution = ABC.optimal_bee.position
    )

Finally, we can use this function in a more sophisticated way in order to visualize the entire optimization process as animated gif.

[6]:
from PIL import Image
from IPython.display import Image as IPImage
from io import BytesIO

plots = []
# Adaptive step in order to have gifs with same number of frames
step = max(1, (ABC.actual_iters+1) // 50) #Note: actual_iters +1 to include initial population
for iteration in range(0,(ABC.actual_iters+1),step):
    plots.append(
        contourplot_bees(
            function         = Schwefel2d,
            bee_colony       = ABC.colony_history[iteration],
            title            = f"{Schwefel2d.name.upper()} optimization [Iteration {iteration} / {ABC.actual_iters}]",
            optimal_solution = Schwefel2d.optimal_solution,
            bounds           = None,
            zoom             = 1.05,
            bee_marker_size  = 55,
            figsize          =(500,500)
        ))

images = []
for fig in plots:
    # Save each figure to a BytesIO object in memory instead of a file
    img_buf = BytesIO()
    fig.write_image(img_buf, format="png", scale=1.5)  # Save the Plotly figure as PNG into the buffer
    img_buf.seek(0)  # Rewind the buffer to the start
    images.append(Image.open(img_buf))  # Open the image from the buffer

# Create the GIF
gif_path = '../_static/animated_optimization.gif'
images[0].save(gif_path, save_all=True, append_images=images[1:], duration=200, loop=0)
IPImage(url=gif_path)

[6]: